package uint16regs

import (
	"MqttCloudProtocolServer/ProtocolServer/mqttlib"
	"MqttCloudProtocolServer/protocols/go/modbus"
	"MqttCloudProtocolServer/publiclib/datamodel/dborm"
	"MqttCloudProtocolServer/publiclib/datastorage"
	"MqttCloudProtocolServer/publiclib/dbcontrol"
	"encoding/json"
	"net"
	"strconv"

	"github.com/wonderivan/logger"
)

type MQTTReportData struct {
	Data         []uint16 `json:"data"`
	Addr         uint16   `json:"addr"`
	Regcount     uint16   `json:"regcount"`
	Funcode      uint16   `json:"funcode"`
	Regstart     uint16   `json:"regstart"`
	ReceiveFrame string   `json:"receive"` //ReceiveFrame
	Time         int      `json:"time"`
}

type MQTTReportInformation struct {
	Projectname    string            `json:"projectname"`
	Projectversion string            `json:"projectversion"`
	Fwversion      string            `json:"fwversion"`
	Cfgversion     string            `json:"cfgversion"`
	Writepoint     []string          `json:"writepoint"`
	Response       []*MQTTReportData `json:"response"`
}

// TCPServer TCP收发服务器
type UInt16DataAnalysis struct {
	mqttlib.OperatorBase
	//tcp          *datamodel.TCPClient
	dbtcp        *dborm.Manageserver
	receiver     func(key string, buffer []uint8)
	isRunning    bool
	dataIndex    map[int]map[int]*modbus.TagInfo
	receiveFrame chan []*MQTTReportData
	sendFrame    chan interface{}
	comFlag      map[uint16]int8 //0:正常 -1:未初始化 1:通讯有错误
}

func (_this *UInt16DataAnalysis) Start() bool {
	//_this.timeout = 2000
	_this.isRunning = true
	_this.receiveFrame = make(chan []*MQTTReportData)
	_this.comFlag = make(map[uint16]int8)
	// for !_this.listenPort(_this.dbtcp.HostIP, _this.dbtcp.HostPort) {
	// 	time.Sleep(time.Second * 5)
	// }
	run := func() {
		for _this.isRunning {
			select {
			case temps := <-_this.receiveFrame:
				for _, temp := range temps {
					for _, tag := range _this.dataIndex[int(temp.Addr)] {
						if tag.RegNo >= int(temp.Regstart) && (tag.RegNo+tag.RegLen) < (int(temp.Regstart)+len(temp.Data)) {
							res := modbus.DataDeal(temp.Data, tag)
							datastorage.GetRedisStorageContent().SaveToRedis("realData", res)
						}
					}
				}
				break
			}
		}
	}
	go run()
	return true
}

// Modify Fun
func (_this *UInt16DataAnalysis) Modify(params interface{}) bool {
	if value, ok := params.(*dborm.Manageserver); ok {
		_this.dbtcp = value
		//return true

		tagsTableControl := dbcontrol.CreateTagesTableControl()
		if tagsTableControl == nil {
			logger.Alert("获取Tags表控制类出错")
			return false
		}

		tages, err := tagsTableControl.GetByIODevice(_this.dbtcp.UUID)
		if err != nil {
			logger.Alert("读取Tags出错:" + err.Error())
			return false
		}
		for _, tag := range tages {
			if tagInfoTemp, err := modbus.AnalysisReadReg(tag.IODevice, tag.Reg, tag.DataType); err == nil {
				if tagInfoTemp == nil {
					continue
				}
				if tempAddr, err := strconv.Atoi(tag.LogicEquipment); err == nil {
					if _, ok := _this.dataIndex[tempAddr]; !ok {
						_this.dataIndex[tempAddr] = make(map[int]*modbus.TagInfo)
					}
					_this.dataIndex[tempAddr][tagInfoTemp.RegNo] = tagInfoTemp
				}
			} else {
				logger.Alert(err.Error())
			}
		}

		//写入寄存器注册回调
		if err := modbus.AnalysisWriteReg(_this.dbtcp.UUID, _this, _this.writeCallback); err != nil {
			logger.Alert(err.Error())
		}
	}
	return false
}
func (_this *UInt16DataAnalysis) GetWriteRegCallback(wcmd, addrs string, regNo int,
	tag *dborm.Tagstable,
	writeCallback func(*modbus.TagForControl) bool) func(string, float64) bool {
	return nil
}

// 数据分析后调用。存在于Redis收到控制命令时，由Redis调用
func (_this *UInt16DataAnalysis) writeCallback(tagPoint *modbus.TagForControl) bool {
	return false
}

//listenPort 监听端口
/*func (_this *UInt16DataAnalysis) listenPort(ip string, port int) bool {
	listener, err := net.Listen("tcp", ip+":"+strconv.Itoa(int(port)))
	_this.listener = listener
	if err != nil {
		logger.Alert("server :: error listen:", err)
		return false
	}
	for _this.isRunning {
		if conn, err := _this.listener.Accept(); err != nil {
			logger.Alert("server :: accept error:", err)
			break
		} else {
			//为了不阻塞新的连接接入，采用协程接收与处理数据
			go _this.receiceData(conn)
			//_this.conns.Push(conn)
		}
	}
	return true
}*/

// receiceData 循环接收数据，通讯管理模式下收到数据后，内部处理，不需要返还发送给mqtt
func (_this *UInt16DataAnalysis) receiceData(conn net.Conn) {
	/*var buffer = make([]byte, 1024)
	var retryCount = 0
	defer conn.Close()
	for _this.isRunning {
		if length, e := conn.Read(buffer); e != nil {
			if e.Error() == "EOF" {
				logger.Debug("读到EOF结束")
				retryCount = 0
				return
			}
			logger.Alert("server :: read error:", e)
			time.Sleep(time.Second)
			retryCount++
			if retryCount > 5 {
				retryCount = 0
				return
			}
		} else {
			logger.Debug("server :: read data ")
			if length < 12 {
				continue
			}
			receiveBuffer := buffer[:length]
			//logger.Alert(_this.GetKey() + ":接收到报文" + helplib.BufferToString(receiveBuffer))
			//model := new(modbus.ModbusModel)
			header := new(modbus.ModbusTCPHeader)
			header.FromArray(receiveBuffer[:6])
			//println(header)
			mmbusModel := new(modbus.ModbusModel)
			mmbusModel.Addr = receiveBuffer[6]
			mmbusModel.Command = modbus.CommandType(receiveBuffer[7])
			mmbusModel.RegNo = uint16(receiveBuffer[8])*256 + uint16(receiveBuffer[9])
			if receiveBuffer[10] != 0 {
				if _, err := conn.Write(append(header.ToArray(), receiveBuffer[6], 0x83, 0x02)); err != nil {
					logger.Alert(err)
				}
				continue
			}
			mmbusModel.RegLength = receiveBuffer[11]
			// if len(receiveBuffer) > 7 {
			// 	if _, err := conn.Write(append(header.ToArray(), receiveBuffer[6], 0x83, 0x02)); err != nil {
			// 		logger.Alert(err)
			// 	}
			// 	continue
			// }
			commandArea := uint16(0)
			switch mmbusModel.Command {
			case modbus.ReadCoilStatus: //CommandType = 1 //00001
				commandArea = 1
				//break
			case modbus.ReadInputStatus: //CommandType = 2 //10001
				commandArea = 10001
				//break
			case modbus.ReadHoldingRegisters: //CommandType = 3 //40001
				commandArea = 40001
				//break
			case modbus.ReadInputRegisters: //CommandType = 4 //30001
				commandArea = 30001
				//break
			}
			content := _this.GetDataSeque(uint16(mmbusModel.Addr), commandArea+mmbusModel.RegNo, uint16(mmbusModel.RegLength))
			if content == nil {
				if _, err := conn.Write(append(header.ToArray(), receiveBuffer[6], 0x83, 0x02)); err != nil {
					logger.Alert(err)
				}
				continue
			}
			contentLen := len(content)
			content = append(append(header.ToArray(), mmbusModel.Addr, byte(mmbusModel.Command), byte(contentLen)), content...)
			if _, err := conn.Write(content); err != nil {
				logger.Alert(err)
				continue
			}
			//for {
			//	if len(_this.frameBuffer) < _this.bufferLen {
			//		break
			//	}
			//	<-_this.frameBuffer
			//}
			//if _this.isRunning {
			//	_this.frameBuffer <- frameObject{buffer[:length], conn, time.Now()}
			//}
			retryCount = 0
		}
	}*/
}

// 获取一个序列的寄存器，返回Bytes
// func (_this *UInt16DataAnalysis) GetDataSeque(addr, startReg, regCount uint16) []uint8 {
// 	var buffer []uint8
// 	if startReg > 30000 && startReg < 50000 {
// 		buffer = make([]uint8, regCount*2)
// 	} else if startReg > 0 && startReg < 20000 {
// 		len := math.Ceil(float64(regCount) / 8)
// 		buffer = make([]uint8, int(len))
// 	} else {
// 		return nil
// 	}
// 	if device, ok := _this.dataRam[addr]; ok {
// 		for i := uint16(0); i < regCount; i++ {
// 			if value, ok := device[startReg+i]; ok {
// 				if startReg > 30000 && startReg < 50000 {
// 					buffer[2*i] = uint8((value & 0xff00) >> 8)
// 					buffer[2*i+1] = uint8(value & 0x00ff)
// 				} else if startReg > 0 && startReg < 20000 {
// 					if value != 0 {
// 						sit := int(math.Floor(float64(i) / 8))
// 						buffer[sit] = buffer[sit] | (1 << (i % 8))
// 					}
// 				} else {
// 					return nil
// 				}
// 			} else {
// 				return nil
// 			}
// 		}
// 		return buffer
// 	} else {
// 		return nil
// 	}
// }

// SendData Fun Modbus管理机模式，收到数据不会主动发到TCP端口，而是内存保存数据
func (_this *UInt16DataAnalysis) SendData(buffer []uint8) bool {
	logger.Trace(string(buffer))
	res := new(MQTTReportInformation)
	if err := json.Unmarshal(buffer, res); err != nil {
		logger.Alert("上报报文错误-" + err.Error())
	} else {
		datas := res.Response
		_this.receiveFrame <- datas
		_this.checkComStatues(datas)
	}
	return true
}
func (_this *UInt16DataAnalysis) checkComStatues(buffer []*MQTTReportData) {
	if len(buffer) == 0 {
		return
	}
	comFlagDic := make(map[uint16]int8)
	for _, data := range buffer {
		if data.Funcode > 4 {
			continue
		}
		//检查通讯状态初始情况
		if _, ok := comFlagDic[data.Addr]; !ok {
			comFlagDic[data.Addr] = -1
		}
		comFlagDic[data.Addr] = modbus.ComCheck(comFlagDic[data.Addr], data.Data != nil && len(data.Data) != 0)
	}
	//命令执行完了，更新通讯状态
	for key, value := range comFlagDic {
		comDis := modbus.GetComDis(value)
		modbus.UpdateComFlag(_this.dbtcp.UUID, int(key), value, comDis)
	}
}

// SetReceive Fun
func (_this *UInt16DataAnalysis) SetReceive(callback func(key string, buffer []uint8)) {
	_this.receiver = callback
}

// Close Fun
func (_this *UInt16DataAnalysis) Close() bool {
	_this.isRunning = false
	close(_this.receiveFrame)
	/*for !_this.conns.IsEmpty() {
		conn := _this.conns.Pull().(net.Conn)
		if err := conn.Close(); err != nil {
			logger.Debug(err)
		}
	}
	if err := _this.listener.Close(); err != nil {
		logger.Error(err)
	}*/
	return true
}
